/*
* 设计一个收银程序 checkCashRegister() ，其把购买价格(price)作为第一个参数 , 付款金额 (cash)作为第二个参数, 和收银机中零钱 (cid) 作为第三个参数.
* cid 是一个二维数组，存着当前可用的找零.
* 当收银机中的钱不够找零时返回字符串 "Insufficient Funds". 如果正好则返回字符串 "Closed".
* */


// const deno = {
//         'PENNY': 1,
//         'NICKEL': 5,
//         'DIME': 10,
//         'QUARTER': 25,
//         'ONE': 100,
//         'FIVE': 500,
//         'TEN': 1000,
//         'TWENTY': 2000,
//         'ONE HUNDRED': 10000
//     };

//找钱系统在行业中，为了避免浮点数的不精确，通通采用整数计算。
function checkCashRegister (price, cash, cid) {
    // 刚刚好
    if(price==cash){
        return "No Need Back";
    }
    // 付款不足
    if (price > cash){
        return "Need More Money";
    }
    var base=100;//金额基数,采用整数计算
    var change=(cash-price)*base; //找零
    //定义一个函数，用来求零钱和。
    var getTotalMoney=function(arr){
        var totalMoney=0;
        arr.reduce(function (preV, currV, currIndex, array){
            totalMoney+=base*(preV[1]+currV[1]);
            return currV;
        });//叠代算法：求零钱之和。
        return totalMoney;
    }
    //余额不足，没法找了
    var remain = getTotalMoney(cid);
    if (remain==change){//如果零钱数等于应找数额，返回closed
        return "Closed";
    }else if(remain < change){//没钱找了
        return "Insufficient Funds";
    };
    // 对应：1角-5角-1元-5元-10元-20元-50元-100元(以元为单位的基础上乘以面值基数：base这里为100)
    var dollar= [1, 5, 10, 25, 100, 500, 1000, 2000, 10000]; // TODO
    var pay={};//保存的key：dollar中面值索引，value：要找的此面值的个数
    var currLast=0;// 当前面值所剩余额
    var currMoney=0;//当前金钱面额(dollar中对应的值)
    for (var i=dollar.length-1;i>=0;i--){//由大到小循环
        //当前面值剩余金额
        currLast=cid[i][1]*base;
        if (currLast<=0) {
            continue;//当前面值的金额剩余0，跳过
        }
        //当前金额面值
        currMoney=dollar[i];
        // 在当前面值下取钱必须同时满足两个条件：
        // 1. 找零必须大于当前面值，比如找零51元，才可以从50里面取钱。
        // 2. 剩余的当前面值的总额足够，比如找4元，但我只有3张1元，就不符合取钱条件
        if(change>currMoney){//如果当前金额面值小于应找钱数
            if(change<currLast){
                // 找零小于当前面值剩余金额：比如找钱51元，当前50面值总额余额还有150元。
                pay[i]=Math.floor(change/currMoney);//取最大张数
                change-=currMoney*pay[i];//取完之后从应找余额中减去（张数x面值）
            }else{
                // 找零大于当前面值剩余金额，比如找零51元，我50元面额总值只有50元
                // 则将所有剩余金额找出
                pay[i]=Math.floor(currLast/currMoney);
                change-=currLast;//就直接减去当前面值剩余所有金额
            }
        }
    }//循环结束之后得到一个pay对象，里面包括了面值和对应应找的钱。
    console.log(pay);
    var res=[];
    // 组织最后需要找零的钱，作为最终返回的数组。
    var keys=Object.keys(pay);//找到pay对象
    var idx=0;
    var total=0;//应找零钱（pay）的总额
    for (var j=0; j<keys.length; j++) {
        // 需要找零的面值索引：比如100，50，20,10...等等
        idx=parseInt([keys[j]]);
        //计算该面值最后找出的零钱(公式：面值x需要找出数量 / 金钱面值基数)
        cid[idx][1]=dollar[idx]*pay[keys[j]]/base;
        res.unshift(cid[idx]);//把结果添加到数组的开头。符合由面值大到小的规律。
        total += dollar[idx]*pay[keys[j]];
        // 顺便计算下这里计算的结果应该和最开始需要找零的金额一致：
        // 面值x需要找出数量——返回到total结果中
    }
    // 找到最后，所有能找的面值加起来还不够
    // 这里与最开始不同，这里是过滤掉了所有找不开的面值
    // 比如：要找0.05元，但是目前剩余一张0.01和1元的面值，依旧判定为找不开
    // 而最开始的是所有余额加起来都不够找
    if (total<change) {
        return "Insufficient Funds";
    }
    console.log(res);
    return res;
}
checkCashRegister(19.50, 20.00, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]);

// function checkCashRegister(price, cash, cid) {
//     //考察浮点数运算
//     // 本题中小于1美元的部分如果直接运算会产生一定的误差。因此所有数都乘以100，最后输出时再除100。
//     const deno = {
//         'PENNY': 1,
//         'NICKEL': 5,
//         'DIME': 10,
//         'QUARTER': 25,
//         'ONE': 100,
//         'FIVE': 500,
//         'TEN': 1000,
//         'TWENTY': 2000,
//         'ONE HUNDRED': 10000
//     };
//     let cidObj = {};
//     let objCopy = {};
//     let keys = Object.keys(deno);
//     let i = keys.length - 1;
//
//     // 找零的钱也要乘以100。
//     let change = (cash - price) * 100;
//     let result = [];
//
//     // 首先把传入的cid的值都乘以100。
//
//     for (let i in cid) {
//         cidObj[cid[i][0]] = cid[i][1] * 100;
//         objCopy[cid[i][0]] = cid[i][1] * 100;
//     }
//
//     // 收银台需要有小于或等于要找的零钱的钱，为此需要获得各种面额的名称以及钱数。判断收银台的钱是否有比要找的钱小的面值，以及此面额是否有钱。
//
//     while (i >= 0) {
//         while (deno[keys[i]] <= change && !!cidObj[keys[i]]) {
//             change -= deno[keys[i]];
//             cidObj[keys[i]] -= deno[keys[i]];
//         }
//         i--;
//     }
//
//     // 如果经过上述循环后，change不为零，则说明找不开。
//
//     if (!!change) {
//         return "Insufficient Funds";
//     }
//
//     // 如果找得开，则判断收银台里是否还有钱。
//     for (let i in cidObj) {
//         if (!!cidObj[i]) {
//             break;
//         } else if (i === keys[keys.length - 1]) {
//             return "Closed";
//         }
//     }
//
//
//     // 如果还有钱，则计算收银台在找完钱后还剩多少钱。这里需要有收银台原来的钱数，故在先前cid传入后多拷贝一个。引用类型需进行深拷贝。
//     for (let i in objCopy) {
//         if (objCopy[i] !== cidObj[i]) {
//             result.unshift([i, (objCopy[i] - cidObj[i]) / 100]);
//         }
//     }
//
//     return result;
// }
//
//
// checkCashRegister(19.50, 20.00, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]);